1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package storm.starter.tools;
19  
20  import org.testng.annotations.DataProvider;
21  import org.testng.annotations.Test;
22  
23  import java.util.Map;
24  
25  import static org.fest.assertions.api.Assertions.assertThat;
26  
27  public class SlotBasedCounterTest {
28  
29    private static final int ANY_NUM_SLOTS = 1;
30    private static final int ANY_SLOT = 0;
31    private static final Object ANY_OBJECT = "ANY_OBJECT";
32  
33    @DataProvider
34    public Object[][] illegalNumSlotsData() {
35      return new Object[][]{ { -10 }, { -3 }, { -2 }, { -1 }, { 0 } };
36    }
37  
38    @Test(expectedExceptions = IllegalArgumentException.class, dataProvider = "illegalNumSlotsData")
39    public void negativeOrZeroNumSlotsShouldThrowIAE(int numSlots) {
40      new SlotBasedCounter<Object>(numSlots);
41    }
42  
43    @DataProvider
44    public Object[][] legalNumSlotsData() {
45      return new Object[][]{ { 1 }, { 2 }, { 3 }, { 20 } };
46    }
47  
48    @Test(dataProvider = "legalNumSlotsData")
49    public void positiveNumSlotsShouldBeOk(int numSlots) {
50      new SlotBasedCounter<Object>(numSlots);
51    }
52  
53    @Test
54    public void newInstanceShouldHaveEmptyCounts() {
55      // given
56      SlotBasedCounter<Object> counter = new SlotBasedCounter<Object>(ANY_NUM_SLOTS);
57  
58      // when
59      Map<Object, Long> counts = counter.getCounts();
60  
61      // then
62      assertThat(counts).isEmpty();
63    }
64  
65    @Test
66    public void shouldReturnNonEmptyCountsWhenAtLeastOneObjectWasCounted() {
67      // given
68      SlotBasedCounter<Object> counter = new SlotBasedCounter<Object>(ANY_NUM_SLOTS);
69      counter.incrementCount(ANY_OBJECT, ANY_SLOT);
70  
71      // when
72      Map<Object, Long> counts = counter.getCounts();
73  
74      // then
75      assertThat(counts).isNotEmpty();
76  
77      // additional tests that go beyond what this test is primarily about
78      assertThat(counts.size()).isEqualTo(1);
79      assertThat(counts.get(ANY_OBJECT)).isEqualTo(1);
80    }
81  
82    @DataProvider
83    public Object[][] incrementCountData() {
84      return new Object[][]{ { new String[]{ "foo", "bar" }, new int[]{ 3, 2 } } };
85    }
86  
87    @Test(dataProvider = "incrementCountData")
88    public void shouldIncrementCount(Object[] objects, int[] expCounts) {
89      // given
90      SlotBasedCounter<Object> counter = new SlotBasedCounter<Object>(ANY_NUM_SLOTS);
91  
92      // when
93      for (int i = 0; i < objects.length; i++) {
94        Object obj = objects[i];
95        int numIncrements = expCounts[i];
96        for (int j = 0; j < numIncrements; j++) {
97          counter.incrementCount(obj, ANY_SLOT);
98        }
99      }
100 
101     // then
102     for (int i = 0; i < objects.length; i++) {
103       assertThat(counter.getCount(objects[i], ANY_SLOT)).isEqualTo(expCounts[i]);
104     }
105     assertThat(counter.getCount("nonexistentObject", ANY_SLOT)).isEqualTo(0);
106   }
107 
108   @Test
109   public void shouldReturnZeroForNonexistentObject() {
110     // given
111     SlotBasedCounter<Object> counter = new SlotBasedCounter<Object>(ANY_NUM_SLOTS);
112 
113     // when
114     counter.incrementCount("somethingElse", ANY_SLOT);
115 
116     // then
117     assertThat(counter.getCount("nonexistentObject", ANY_SLOT)).isEqualTo(0);
118   }
119 
120   @Test
121   public void shouldIncrementCountOnlyOneSlotAtATime() {
122     // given
123     int numSlots = 3;
124     Object obj = Long.valueOf(10);
125     SlotBasedCounter<Object> counter = new SlotBasedCounter<Object>(numSlots);
126 
127     // when (empty)
128     // then
129     assertThat(counter.getCount(obj, 0)).isEqualTo(0);
130     assertThat(counter.getCount(obj, 1)).isEqualTo(0);
131     assertThat(counter.getCount(obj, 2)).isEqualTo(0);
132 
133     // when
134     counter.incrementCount(obj, 1);
135 
136     // then
137     assertThat(counter.getCount(obj, 0)).isEqualTo(0);
138     assertThat(counter.getCount(obj, 1)).isEqualTo(1);
139     assertThat(counter.getCount(obj, 2)).isEqualTo(0);
140   }
141 
142   @Test
143   public void wipeSlotShouldSetAllCountsInSlotToZero() {
144     // given
145     SlotBasedCounter<Object> counter = new SlotBasedCounter<Object>(ANY_NUM_SLOTS);
146     Object countWasOne = "countWasOne";
147     Object countWasThree = "countWasThree";
148     counter.incrementCount(countWasOne, ANY_SLOT);
149     counter.incrementCount(countWasThree, ANY_SLOT);
150     counter.incrementCount(countWasThree, ANY_SLOT);
151     counter.incrementCount(countWasThree, ANY_SLOT);
152 
153     // when
154     counter.wipeSlot(ANY_SLOT);
155 
156     // then
157     assertThat(counter.getCount(countWasOne, ANY_SLOT)).isEqualTo(0);
158     assertThat(counter.getCount(countWasThree, ANY_SLOT)).isEqualTo(0);
159   }
160 
161   @Test
162   public void wipeZerosShouldRemoveAnyObjectsWithZeroTotalCount() {
163     // given
164     SlotBasedCounter<Object> counter = new SlotBasedCounter<Object>(2);
165     int wipeSlot = 0;
166     int otherSlot = 1;
167     Object willBeRemoved = "willBeRemoved";
168     Object willContinueToBeTracked = "willContinueToBeTracked";
169     counter.incrementCount(willBeRemoved, wipeSlot);
170     counter.incrementCount(willContinueToBeTracked, wipeSlot);
171     counter.incrementCount(willContinueToBeTracked, otherSlot);
172 
173     // when
174     counter.wipeSlot(wipeSlot);
175     counter.wipeZeros();
176 
177     // then
178     assertThat(counter.getCounts()).doesNotContainKey(willBeRemoved);
179     assertThat(counter.getCounts()).containsKey(willContinueToBeTracked);
180   }
181 }